package com.tticar.invmanager.service.impl;

import com.baomidou.mybatisplus.entity.Columns;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.mapper.Wrapper;
import com.baomidou.mybatisplus.plugins.Page;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import com.tticar.invmanager.common.Enum.CodeType;
import com.tticar.invmanager.common.Enum.PayBusinessType;
import com.tticar.invmanager.common.Enum.Status;
import com.tticar.invmanager.common.shiro.MySecurityUtils;
import com.tticar.invmanager.common.utils.DateUtils;
import com.tticar.invmanager.common.utils.ServiceUtil;
import com.tticar.invmanager.common.utils.date.DateStyle;
import com.tticar.invmanager.common.utils.date.DateUtil;
import com.tticar.invmanager.entity.*;
import com.tticar.invmanager.entity.vo.MyPage;
import com.tticar.invmanager.entity.vo.PurchaseAddDto;
import com.tticar.invmanager.entity.vo.PurchaseGoodsDto;
import com.tticar.invmanager.entity.vo.PurchaseSearchDto;
import com.tticar.invmanager.mapper.PPurchaseMapper;
import com.tticar.invmanager.service.*;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.util.Strings;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * <p>
 * 采购单 服务实现类
 * </p>
 *
 * @author joeyYan
 * @since 2018-08-03
 */
@Service
public class PPurchaseServiceImpl extends ServiceImpl<PPurchaseMapper, PPurchase> implements IPPurchaseService {

    @Autowired
    private ICodeCounterService codeCounterService;

    @Autowired
    private IWRelativeUnitService relativeUnitService;

    @Autowired
    private ISaleReturnService saleReturnService;

    @Autowired
    private IMMaterielSkuService materielSkuService;

    @Autowired
    private IPPurchaseDetailService purchaseDetailService;

    @Autowired
    private IInRepositoryDetailService inRepositoryDetailService;

    @Autowired
    private IRepositoryCountService repositoryCountService;

    @Autowired
    private IPPayService payService;

    @Override
    public Page selectPage(PPurchase pPurchase, MyPage<PPurchase> page) {

        List<Map> maps = this.baseMapper.queryIncomeList(page, pPurchase);
        page.setRecords(maps);
        return page;
    }

    @Override
    public Page selectExpendPage(PPurchase pPurchase, MyPage<PPurchase> page) {

        List<Map> maps = this.baseMapper.queryExpendList(page, pPurchase);
        page.setRecords(maps);
        return page;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delete(List<Long> ids) {
        List list = new ArrayList();
        for (Long id : ids) {
            PPurchase pPurchase = new PPurchase();
            pPurchase.setId(id);
            //删除为-1，区分删除和禁用
            pPurchase.setStatus(1);
            list.add(pPurchase);
        }
        this.updateBatchById(list);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void addPurchase(PurchaseAddDto dto) throws ParseException {
        if (dto.getRealPay() == null) {
            dto.setRealPay(BigDecimal.ZERO);
        }
        //根据供应商id拆分成不同list
        List<PurchaseGoodsDto> goodsList = dto.getGoodsList();
        Map<Long, List<PurchaseGoodsDto>> keyMap = new HashMap<>();
        for (PurchaseGoodsDto goods : goodsList) {
            goods.setRalativeId(dto.getRelativeId());//改版后统一供应商
            Long key = goods.getRalativeId();
            if (keyMap.containsKey(key)) {
                keyMap.get(key).add(goods);
            } else {
                List<PurchaseGoodsDto> tmpList = new ArrayList<>();
                tmpList.add(goods);
                keyMap.put(key, tmpList);
            }
        }

        Date now = new Date();
        String rkCode = codeCounterService.getOrderCode(CodeType.RK);
        for (Long key : keyMap.keySet()) {
            PPurchase purchase = new PPurchase();
            purchase.setPtype(dto.getPurchaseType());
            purchase.setCode(codeCounterService.getOrderCode(CodeType.CGLX01));
            purchase.setRelativeId(dto.getRelativeId());

            WRelativeUnit unit = relativeUnitService.selectById(key);
            purchase.setContactTel(unit.getTel());
            purchase.setContactName(unit.getContactor());
            purchase.setUsername(MySecurityUtils.currentUser().getUsername());
            purchase.setPayStatus(0);
            if (dto.getType() == 1) {
                purchase.setPayStatus(keyMap.get(key).get(0).getPayStatus());//每个供应商下的商品支付状态一致
            }
            purchase.setOrderStatus(dto.getType() == 0 ? 0 : 1);
            purchase.setCtime(now);
            purchase.setPtime(DateUtil.StringToDate(dto.getPtime(), DateStyle.YYYY_MM_DD));

            BigDecimal amountTotal = BigDecimal.ZERO;
            BigDecimal amountActualTotal = BigDecimal.ZERO;
            Integer totalNum = 0;

            List<PPurchaseDetail> detailList = new ArrayList<>();
            Map<Long, Map<String, Long>> kwMap = new HashMap<>();//记录规格-库位
            for (PurchaseGoodsDto goods : keyMap.get(key)) {
                PPurchaseDetail detail = new PPurchaseDetail();
                detail.setSkuId(goods.getSkusId());
                detail.setCount(goods.getCount());
                detail.setCountActual(goods.getCount());
                detail.setAmount(new BigDecimal(goods.getAmount()));
                detail.setAmountActual(new BigDecimal(goods.getAmountActual()));
                String price = goods.getAmount().toString();
                amountTotal = amountTotal.add(new BigDecimal(price).multiply(new BigDecimal(goods.getCount())).setScale(2));
                String price1 = goods.getAmountActual().toString();
                amountActualTotal = amountActualTotal.add(new BigDecimal(price1).multiply(new BigDecimal(goods.getCount())).setScale(2));
                totalNum += detail.getCountActual();
                //弃用库位批次
//                detail.setWearhouseId(goods.getWearhouseId());
//                detail.setPositionId(goods.getPositionId());
//                detail.setBatchCode(StringUtils.isBlank(goods.getBatchCode()) ? codeCounterService.getBatchCode() : goods.getBatchCode());
                detail.setWearhouseId(goods.getRepositoryId());
                detail.setRemark(goods.getRemark());
                detail.setCtime(now);
                detailList.add(detail);

                //入库
                if (dto.getType() == 1) {
                    Map<String, Long> tmp = new HashMap<>();
                    tmp.put("wearhouseId", goods.getRepositoryId());
//                    tmp.put("positionId", goods.getPositionId());
                    kwMap.put(goods.getSkusId(), tmp);
                }
            }

            purchase.setTotalNum(totalNum);
            purchase.setAmount(amountTotal);
            purchase.setAmountActual(amountActualTotal);
//            purchase.setPayStatus(dto.getPayStatus());
            //是入库
            if (dto.getType() == 1) {
                purchase.setAmountAlready(dto.getRealPay());
                if (dto.getRealPay() != null && dto.getRealPay().compareTo(dto.getTotalMoney()) >= 0) {
                    purchase.setPayStatus(1);
                } else {
                    purchase.setAmountIng(dto.getTotalMoney().subtract(dto.getRealPay()));
                }

            } else {
//                purchase.setAmountAlready(dto.getRealPay());
                purchase.setAmountIng(dto.getRealPay());
            }
            purchase.setRemark(dto.getRemark());
            purchase.setSettlementStatus(dto.getPayStatus());
            this.insert(purchase);

            Long purchaseId = purchase.getId();

            for (PPurchaseDetail detail : detailList) {
                detail.setPurchaseId(purchaseId);
                this.purchaseDetailService.insert(detail);
                Long detailId = detail.getId();

                //入库
                if (dto.getType() == 1) {
                    //入库更新采购总量和平均采购价格
                    Wrapper wrapper = new EntityWrapper<>();
                    wrapper.eq("id", detail.getSkuId());
                    MMaterielSku mMaterielSku = materielSkuService.selectOne(wrapper);
                    BigDecimal avgBuyPrice = mMaterielSku.getAvgBuyPrice() == null ? BigDecimal.ZERO : mMaterielSku.getAvgBuyPrice();
                    Long buyTotalNum = mMaterielSku.getBuyTotalNum() == null ? 0L : mMaterielSku.getBuyTotalNum();
                    buyTotalNum = buyTotalNum + detail.getCount();
                    avgBuyPrice = (avgBuyPrice.multiply(new BigDecimal(buyTotalNum - detail.getCount())).add(detail.getAmountActual()
                            .multiply(new BigDecimal(detail.getCount())))).divide(new BigDecimal(buyTotalNum),2,BigDecimal.ROUND_HALF_DOWN);
                    mMaterielSku.setAvgBuyPrice(avgBuyPrice);
                    mMaterielSku.setBuyTotalNum(buyTotalNum);
                    materielSkuService.updateById(mMaterielSku);

                    Map<String, Long> kw = kwMap.get(detail.getSkuId());
                    InRepositoryDetail inDetail = new InRepositoryDetail();
                    inDetail.setSkuId(detail.getSkuId());
                    inDetail.setCode(rkCode);
                    inDetail.setBuszId(detailId);
                    inDetail.setProviderId(purchase.getRelativeId());
//                    inDetail.setBatchNumber(detail.getBatchCode());
                    inDetail.setWearhouseId(kw.get("wearhouseId"));
//                    inDetail.setPositionId(kw.get("positionId"));
                    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
                    inDetail.setOrderTime(sdf.parse(dto.getPtime()));
                    inDetail.setType(0);
                    inDetail.setCount(detail.getCountActual());
                    inDetail.setRemark(detail.getRemark());
                    inDetail.setStatus(0);
                    inDetail.setCtime(now);
                    inDetail.setRemark(purchase.getRemark());
                    inDetail.setUsername(MySecurityUtils.currentUser().getUsername());
                    inRepositoryDetailService.insertOrUpdate(inDetail);

                    repositoryCountService.updateRepositoryCount(detail.getSkuId(), inDetail.getWearhouseId(), inDetail.getCount());
                }
            }
        }
    }

    @Override
    public List<Map> getPurchaseDetailList(Long purchaseId) {
        return this.baseMapper.getPurchaseDetailList(purchaseId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void pay(Long salesId, BigDecimal payFee, Integer payType, String payRemark) {
        PPurchase purchase = this.selectById(salesId);
        PPay pay = new PPay();
        pay.setBusinessType(PayBusinessType.PURCHASE.getCode());
        pay.setBusinessId(salesId);
        pay.setType(payType);
        pay.setAmount(payFee);
        pay.setRemainAmount(purchase.getAmountIng().subtract(payFee));
        pay.setFeeNote("采购支付");
        pay.setRemark(payRemark);
        pay.setFeeType(0);
        pay.setUseType(0);
        pay.setStatus(0);
        pay.setUsername(ServiceUtil.getLoginUserName());
        this.payService.insert(pay);

        purchase.setAmountAlready(purchase.getAmountAlready().add(payFee));
        purchase.setAmountIng(purchase.getAmountIng().subtract(payFee));
        if (purchase.getAmountIng().compareTo(BigDecimal.ZERO) == 0) {
            purchase.setPayStatus(1);
            if (purchase.getOrderStatus() == 1) {
                purchase.setOrderStatus(2);
            }
        }
        this.updateById(purchase);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void inRepository(Long purchaseId) {
        PPurchase purchase = this.selectById(purchaseId);
        purchase.setOrderStatus(purchase.getPayStatus() == 0 ? 1 : 2);
        this.baseMapper.updateById(purchase);

        Wrapper wrapper = new EntityWrapper();
        wrapper.eq("purchase_id", purchaseId);
        List<PPurchaseDetail> list = this.purchaseDetailService.selectList(wrapper);

        Date now = new Date();
        String rkCode = codeCounterService.getOrderCode(CodeType.RK);
        for(PPurchaseDetail detail : list) {
            InRepositoryDetail inDetail = new InRepositoryDetail();
            inDetail.setSkuId(detail.getSkuId());
            inDetail.setCode(rkCode);
            inDetail.setBuszId(detail.getId());
            inDetail.setProviderId(purchase.getRelativeId());
            inDetail.setBatchNumber(detail.getBatchCode());
            inDetail.setWearhouseId(detail.getWearhouseId());
            inDetail.setPositionId(detail.getPositionId());
            inDetail.setOrderTime(purchase.getPtime());
            inDetail.setType(0);
            inDetail.setCount(detail.getCountActual());
            inDetail.setRemark(detail.getRemark());
            inDetail.setStatus(0);
            inDetail.setCtime(now);
            inDetail.setUsername(MySecurityUtils.currentUser().getUsername());
            inRepositoryDetailService.insertOrUpdate(inDetail);

            repositoryCountService.updateRepositoryCount(detail.getSkuId(), inDetail.getWearhouseId(), inDetail.getCount());
        }
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void inRepositoryNewVersion(Long purchaseId, List<PurchaseGoodsDto> goodsList,BigDecimal realPay,BigDecimal totalMoney,Integer payStatus,String remark) {
        PPurchase purchase = this.selectById(purchaseId);
        purchase.setOrderStatus(1);

        //入库进行结算操作
        purchase.setPayStatus(payStatus);
        if (realPay!=null && realPay.compareTo(totalMoney) >= 0) {
            purchase.setPayStatus(1);
        }
        purchase.setRemark(remark);
        purchase.setAmountActual(totalMoney);
        purchase.setAmountAlready(realPay);
        if (totalMoney.compareTo(realPay) > 0 && purchase.getPayStatus() == 0) {
            purchase.setAmountIng(totalMoney.subtract(realPay));
        } else {
            purchase.setAmountIng(BigDecimal.ZERO);
        }



        Wrapper wrapper = new EntityWrapper();
        wrapper.eq("purchase_id", purchaseId);
        List<PPurchaseDetail> list = this.purchaseDetailService.selectList(wrapper);
        double total = 0;
        for (PPurchaseDetail detailFromDB : list) {
            for (PurchaseGoodsDto goodsFromPage : goodsList) {
                if (detailFromDB.getSkuId().equals(goodsFromPage.getSkuId())) {
                    detailFromDB.setCountActual(goodsFromPage.getCount());
                    detailFromDB.setCount(goodsFromPage.getCount());
                    detailFromDB.setAmountActual(new BigDecimal(goodsFromPage.getAmountActual().toString()));
                    total += goodsFromPage.getCount() * goodsFromPage.getAmountActual();
                    break;
                }
            }
            //采购入库时更新均价，采购总数
            Wrapper<MMaterielSku> wrapperSku = new EntityWrapper<>();
            wrapperSku.eq("id", detailFromDB.getSkuId());
            MMaterielSku mMaterielSku = materielSkuService.selectOne(wrapperSku);
            BigDecimal avgBuyPrice = mMaterielSku.getAvgBuyPrice() == null ? BigDecimal.ZERO : mMaterielSku.getAvgBuyPrice();
            Long buyTotalNum = mMaterielSku.getBuyTotalNum() == null ? 0L : mMaterielSku.getBuyTotalNum();
            buyTotalNum = buyTotalNum + detailFromDB.getCount();
            avgBuyPrice = (avgBuyPrice.multiply(new BigDecimal(buyTotalNum - detailFromDB.getCount())).add(detailFromDB.getAmountActual()
                    .multiply(new BigDecimal(detailFromDB.getCount())))).divide(new BigDecimal(buyTotalNum),2,BigDecimal.ROUND_HALF_UP);
            mMaterielSku.setAvgBuyPrice(avgBuyPrice);
            mMaterielSku.setBuyTotalNum(buyTotalNum);
            materielSkuService.updateById(mMaterielSku);
        }
        purchase.setAmountActual(new BigDecimal(total));
        purchaseDetailService.updateBatchById(list);
        this.baseMapper.updateById(purchase);

        Date now = new Date();
        String rkCode = codeCounterService.getOrderCode(CodeType.RK);
        for(PPurchaseDetail detail : list) {
            InRepositoryDetail inDetail = new InRepositoryDetail();
            inDetail.setSkuId(detail.getSkuId());
            inDetail.setCode(rkCode);
            inDetail.setBuszId(detail.getId());
            inDetail.setProviderId(purchase.getRelativeId());
            inDetail.setWearhouseId(detail.getWearhouseId());
            inDetail.setOrderTime(purchase.getPtime());
            inDetail.setType(0);
            inDetail.setCount(detail.getCountActual());
            inDetail.setRemark(detail.getRemark());
            inDetail.setStatus(0);
            inDetail.setCtime(now);
            inDetail.setUsername(MySecurityUtils.currentUser().getUsername());
            inDetail.setRemark(purchase.getRemark());
            inRepositoryDetailService.insertOrUpdate(inDetail);

            repositoryCountService.updateRepositoryCount(detail.getSkuId(), inDetail.getWearhouseId(), inDetail.getCount());
        }
    }

    /**
     * 结算
     * */
    @Override
    public void endCountPurchase(Long purchaseId, BigDecimal realPay, BigDecimal totalMoney, Integer payStatus, String remark) {
        PPurchase purchase = this.selectById(purchaseId);
//        purchase.setOrderStatus(purchase.getPayStatus() == 0 ? 1 : 2);
//        purchase.setPayStatus(payStatus);
//        if (realPay.compareTo(totalMoney) >= 0) {
//            purchase.setPayStatus(1);
//        }
//        purchase.setRemark(remark);
//        purchase.setAmountActual(totalMoney);
//        purchase.setAmountAlready(realPay);
        purchase.setPayStatus(1);
        purchase.setAmountActual(totalMoney);
        purchase.setAmountAlready(totalMoney);
        purchase.setAmountIng(BigDecimal.ZERO);
        this.baseMapper.updateById(purchase);
    }

    /**
     * 撤销入库
     * */
    @Override
    @Transactional
    public void cancelInPurchase(Long purchaseId) {
        PPurchase purchase = this.selectById(purchaseId);
        purchase.setOrderStatus(0);
        Wrapper wrapper = new EntityWrapper<>();
        wrapper.eq("purchase_id", purchaseId);
        List<PPurchaseDetail> pPurchaseDetails = purchaseDetailService.selectList(wrapper);
        List idList = new ArrayList<>();
        for (PPurchaseDetail dto : pPurchaseDetails) {
            idList.add(dto.getId());

            //撤销入库的时候，更新平均采购价格和减少采购总数
            Wrapper wrapperSku = new EntityWrapper<>();
            wrapperSku.eq("id", dto.getSkuId());
            MMaterielSku mMaterielSku = materielSkuService.selectOne(wrapperSku);
            BigDecimal avgBuyPrice = mMaterielSku.getAvgBuyPrice() == null ? BigDecimal.ZERO : mMaterielSku.getAvgBuyPrice();
            Long buyTotalNum = mMaterielSku.getBuyTotalNum() == null ? 0L : mMaterielSku.getBuyTotalNum();
            buyTotalNum = buyTotalNum - dto.getCount() < 0 ? 0 : buyTotalNum - dto.getCount();
            if (buyTotalNum != 0) {
                avgBuyPrice = (avgBuyPrice.multiply(new BigDecimal(buyTotalNum + dto.getCount())).subtract(dto.getAmountActual()
                        .multiply(new BigDecimal(dto.getCount())))).divide(new BigDecimal(buyTotalNum), 2, BigDecimal.ROUND_HALF_DOWN);
                mMaterielSku.setAvgBuyPrice(avgBuyPrice);
                mMaterielSku.setBuyTotalNum(buyTotalNum);
            } else {
                mMaterielSku.setAvgBuyPrice(BigDecimal.ZERO);
                mMaterielSku.setBuyTotalNum(0L);
            }
            materielSkuService.updateById(mMaterielSku);
        }
        Wrapper wrapperInRepository = new EntityWrapper<>();
        wrapperInRepository.in("busz_id", idList);
        wrapperInRepository.eq("type", 0);
        wrapperInRepository.eq("status", 0);
        List<InRepositoryDetail> inRepositoryDetails = inRepositoryDetailService.selectList(wrapperInRepository);
        for (InRepositoryDetail inDetail : inRepositoryDetails) {
            inDetail.setStatus(-1);
            repositoryCountService.updateRepositoryCount(inDetail.getSkuId(),inDetail.getWearhouseId(),inDetail.getCount() * -1);
        }
        inRepositoryDetailService.updateBatchById(inRepositoryDetails);

        purchase.setAmountIng(purchase.getAmountAlready());
        purchase.setAmountAlready(BigDecimal.ZERO);
        purchase.setPayStatus(0);
        this.baseMapper.updateById(purchase);
    }

    /**
     * 撤销结算
     * */
    @Override
    @Transactional
    public void cancelPurchaseEnd(Long purchaseId) {
        PPurchase purchase = this.selectById(purchaseId);
        purchase.setPayStatus(0);
        purchase.setAmountAlready(BigDecimal.ZERO);
        this.baseMapper.updateById(purchase);
    }

    @Override
    public Page search(PurchaseSearchDto searchDto, MyPage<PPurchase> page) {
        return page.setRecords(this.baseMapper.search(searchDto, page));
    }


    /**
     * 结算应付款单
     * */
    @Override
    public void endCountForExpend(List<String> codes) {
        for (String code : codes) {
            if (code.contains("CG")) {
                Wrapper wrapper = new EntityWrapper<>();
                wrapper.eq("code", code);
                PPurchase pPurchase = this.selectOne(wrapper);
                pPurchase.setPayStatus(1);
                pPurchase.setAmountAlready(pPurchase.getAmountActual());
                this.updateById(pPurchase);
            } else if (code.contains("XT")) {
                Wrapper wrapper = new EntityWrapper<>();
                wrapper.eq("code", code);
                List<SaleReturn> saleReturns = saleReturnService.selectList(wrapper);
                BigDecimal totalMoney = BigDecimal.ZERO;
                for (SaleReturn entity : saleReturns) {
                    totalMoney = totalMoney.add(entity.getUnitPrice().multiply(new BigDecimal(entity.getCount())));
                }
                for (SaleReturn entity : saleReturns) {
                    entity.setPayStatus(1);
                    entity.setRealPay(totalMoney);
                }
                saleReturnService.updateBatchById(saleReturns);
            }
        }
    }
}
